package net.yambal.component
{
        import flash.desktop.NativeApplication;
        import flash.desktop.Updater;
        import flash.display.NativeWindowSystemChrome;
        import flash.events.Event;
        import flash.events.EventDispatcher;
        import flash.events.IOErrorEvent;
        import flash.filesystem.File;
        import flash.filesystem.FileMode;
        import flash.filesystem.FileStream;
        import flash.net.URLLoader;
        import flash.net.URLLoaderDataFormat;
        import flash.net.URLRequest;
        
        import mx.core.IMXMLObject;
        
        import net.yambal.component.event.AutoUpdaterEvent;
        
        [Event(name="version_xml_io_error", type="net.yambal.component.event.AutoUpdaterEvent")]
        [Event(name="air_file_io_error", type="net.yambal.component.event.AutoUpdaterEvent")]
        [Event(name="is_current_version", type="net.yambal.component.event.AutoUpdaterEvent")]
        [Event(name="can_update", type="net.yambal.component.event.AutoUpdaterEvent")]
        [Event(name="escape_update", type="net.yambal.component.event.AutoUpdaterEvent")]
        [Event(name="version_xml_parse_error", type="net.yambal.component.event.AutoUpdaterEvent")]
        public class AutoUpdater extends EventDispatcher implements IMXMLObject{
                private namespace descriptor = 'http://ns.adobe.com/air/application/1.0';

                public var url:String;
                public var main_app_xml_ns:String = "http://ns.adobe.com/air/application/1.5";
                public var auto_window:Boolean = false;
                
                public var initialized_start:Boolean = false;
                
                private var _can_update:Boolean = false;
                
                private var remoteVersion:String;
                private var airUrl:String;
                private var airLoader:URLLoader;
                private var versionLoader:URLLoader;
                
                private var _progress:UpdateDLProgress;

                
                private var _nowVersion:String;
                private var _appName:String;
                
                public function AutoUpdater()
                {
                }

                public function initialized(document:Object, id:String):void {
                	trace("AutoUpdater - - - - - -(" + this + ")");
                		trace("\tinitialized_start = " + this.initialized_start);
                	if(this.initialized_start){
                		trace("\tstart");
                		this.checkVersion();
                	}else{
                		trace("\tskip");
                	}
                }
                
                public function checkVersion():void{
                    default xml namespace = new Namespace(this.main_app_xml_ns);
                    this._nowVersion = NativeApplication.nativeApplication.applicationDescriptor.version;
                    
                    this._appName = NativeApplication.nativeApplication.applicationDescriptor.name;
                    
                    versionLoader = new URLLoader();
                    versionLoader.addEventListener(Event.COMPLETE, versionCheckCompleteHandler);
                    versionLoader.addEventListener(IOErrorEvent.IO_ERROR, versionCheckIOErrorHandler);
                    versionLoader.load(new URLRequest(url));
                    
                    trace("■AutoUpDaterについて");
                    trace("バージョンはapp.xmlのversionで管理する");
                    trace("*イベント");
                    trace("\tversion_xml_io_error：\tバージョンXMLに到達できなかった");
                    trace("\tis_current_version：\tバージョンは最新です");
                    trace("\tcan_update：\t\tアップデート可能です");
                    trace("\tescape_update：\t\tユーザの操作によってアップデートをしない");
                    trace("\tair_file_io_error：\t\tアップデートAirファイルをダウンロードできなかった");
                    trace("*メソッド");
                    trace("\tdownloadAirFile：\t更新を開始する（can_updateを受けて...）");
                    trace("*メンバ");
                    trace("\turl[String]：\t\tバージョンXML公開先");
                    trace("\tauto_window[true|false]：自動で更新確認Windowを表示する\n");
                    
                    trace("■このアプリケーションのバージョンについて");
                    trace("新しいバージョンXML公開先");
                    trace(this.url);
                    trace("新しいバージョンのXML\n------------------------");
                    trace("<version>");
                    trace("\t<version>" + this._nowVersion + "</version>");
                    trace("\t<url>{最新(この)AirファイルのURL}</url>");
                    trace("</version>\n------------------------\n");
                }
                
                /////////////// Events ////////////////
                /**
                 * AirファイルのDLのCompleteHandler
                 */
                private function downloadAirFileCompleteHandler(event:Event):void {
                        this._progress.close();
                        
                        var airFile:File = File.applicationStorageDirectory.resolvePath("updateFile.air");
                        var fs:FileStream = new FileStream();
                        fs.open(airFile, FileMode.WRITE);
                        fs.writeBytes(airLoader.data);
                        fs.close();

                        var updater:Updater = new Updater();
                        updater.update(airFile, remoteVersion);
                }

                /**
                 * AirファイルのDLのIOErrorEvent
                 */
                private function downloadAirFileIOErrorHandler(event:IOErrorEvent):void {
                        this.dispatchEvent(new AutoUpdaterEvent(AutoUpdaterEvent.AIR_FILE_IO_ERROR, this._nowVersion, this.remoteVersion));
                        
                        if(this.auto_window){
                                var air_io_Win:UpdateCheckWin = new UpdateCheckWin();
                                air_io_Win.systemChrome = NativeWindowSystemChrome.NONE;
                                air_io_Win.open();
                                air_io_Win.maximize();
                        }
                }

                /**
                 * アップデートチェックのCompleteHandler
                 */
                private function versionCheckCompleteHandler(event:Event):void {
                		try{
                        	var xml:XML = new XML(versionLoader.data);
                  		}catch(e:Error){
                  			this.dispatchEvent(new AutoUpdaterEvent(AutoUpdaterEvent.VERSION_XML_PARSE_ERROR,null));
                  			return;
                  		}
                  		
                        remoteVersion = xml.version;
                        airUrl = xml.url;
                        
                        trace("ロカーカルVer:" + remoteVersion + "<>リモートVer:" + this._nowVersion);
                        
                        if(remoteVersion == this._nowVersion){
                                // 実行中のヴァージョンは最新
                                this.dispatchEvent(new AutoUpdaterEvent(AutoUpdaterEvent.IS_CURRENT_VERSION, this._nowVersion, this.remoteVersion));
                                
                        }else {
                                // 実行中のヴァージョンは最新ではない
                                this._can_update = true;        // アップデート可能フラグ
                                this.dispatchEvent(new AutoUpdaterEvent(AutoUpdaterEvent.CAN_UPDATE, this._nowVersion, this.remoteVersion));
                                
                                if(this.auto_window){
                                        // アップデートを行うか確認するWindow
                                        var checkWin:UpdateCheckWin = new UpdateCheckWin();
                                        checkWin._myParent = this;
                                        checkWin.setVersion(this._appName, this._nowVersion, remoteVersion);
                                        checkWin.systemChrome = NativeWindowSystemChrome.NONE;
                                        checkWin.open();
                                        checkWin.maximize();
                                }
                        }
                }
                
                /**
                 * アップデートチェックのIOErrorEvent
                 *              アップデートをチェックするXMLに到達できなかった
                 *              ただし、オフライン状態も含める
                 */
                private function versionCheckIOErrorHandler(event:IOErrorEvent):void {
                        this.dispatchEvent(new AutoUpdaterEvent(AutoUpdaterEvent.VERSION_XML_IO_ERROR, this._nowVersion));
                }

                /////////////// Methods ////////////////
                /**
                 * airファイルをダウンロードする
                 */
                public function downloadAirFile():void {
                        if(this._can_update){
                                // アップデートできるフラグが立っていたら
                                // auto_windowモードでは無いときに、手動でこのメソッドを呼ぶので...
                                airLoader = new URLLoader();
                                airLoader.dataFormat = URLLoaderDataFormat.BINARY;
                                airLoader.addEventListener(Event.COMPLETE, downloadAirFileCompleteHandler);
                                airLoader.addEventListener(IOErrorEvent.IO_ERROR, downloadAirFileIOErrorHandler);
                                airLoader.load(new URLRequest(airUrl));
                        }

                        this._progress = new UpdateDLProgress();
                        this._progress.systemChrome = NativeWindowSystemChrome.NONE;
                        this._progress.open();
                        this._progress.maximize();
                }
                
                public function escapeUpdate():void{
                        this.dispatchEvent(new AutoUpdaterEvent(AutoUpdaterEvent.ESCAPE_UPDATE, this._nowVersion));
                }
                
                /**
                 * 現在のバージョン（app-xmlに記述されたもの）を返す
                 **/
                [Bindable]
                public function get version():String{
                        return this._nowVersion;
                }
                
                public function set version(s:String):void{

                }
        }
}